using System.Windows.Forms;
using NUnit.Framework;
using Rhino.Mocks;
using ShadeTree.Binding.Drivers;
using ShadeTree.Binding.Elements;
using ShadeTree.Binding.Stylers;

namespace ShadeTree.Binding.Tests
{
    [TestFixture]
    public class Copying_settings_from_one_screen_element_to_another
    {
        [Test]
        public void Copy_from_ScreenBinder_when_the_element_can_be_found()
        {
            var control = new Control();

            var newElement = new ScreenElement<Control>(control);
            var originalElement = new ScreenElement<Control>(control);
            originalElement.Alias = "some alias";
            originalElement.Label = ControlDriverFactory.GetDriver(new Label());
            originalElement.PostLabel = ControlDriverFactory.GetDriver(new Label());

            var mocks = new MockRepository();
            var binder = mocks.StrictMock<IScreenBinder>();
            using (mocks.Record())
            {
                Expect.Call(binder.FindElementForControl(control)).Return(originalElement);
            }

            using (mocks.Playback())
            {
                newElement.CopyFrom(binder);
                newElement.Alias.ShouldEqual(originalElement.Alias);
                newElement.Label.ShouldEqual(originalElement.Label);
                newElement.PostLabel.ShouldEqual(originalElement.PostLabel);
            }
        }

        [Test]
        public void Copy_the_label_alias_and_post_label()
        {
            var control = new Control();

            var newElement = new ScreenElement<Control>(control);
            var originalElement = new ScreenElement<Control>(control);
            originalElement.Alias = "some alias";
            originalElement.Label = ControlDriverFactory.GetDriver(new Label());
            originalElement.PostLabel = ControlDriverFactory.GetDriver(new Label());

            newElement.CopyFrom(originalElement);
            newElement.Alias.ShouldEqual(originalElement.Alias);
            newElement.Label.ShouldEqual(originalElement.Label);
            newElement.PostLabel.ShouldEqual(originalElement.PostLabel);
        }

        [Test]
        public void Try_to_copy_from_ScreenBinder_and_do_not_blow_up_when_Element_is_not_found()
        {
            var control = new Control();
            var newElement = new ScreenElement<Control>(control);

            var mocks = new MockRepository();
            var binder = mocks.StrictMock<IScreenBinder>();
            using (mocks.Record())
            {
                Expect.Call(binder.FindElementForControl(control)).Return(null);
            }

            using (mocks.Playback())
            {
                newElement.CopyFrom(binder);
            }
        }
    }

    [TestFixture]
    public class When_creating_a_new_ScreenElement
    {
        [Test]
        public void Apply_style_to_the_control()
        {
            Label theLabelBeingStyled = null;
            var label = new Label();

            Styler.Default.ClearAll();
            Styler.Default.UseStyleFor<Label>(l => theLabelBeingStyled = l);

            var element = new ScreenElement<Label>(label);

            theLabelBeingStyled.ShouldEqual(label);
        }
    }


    [TestFixture]
    public class When_determining_the_display_state_of_a_ScreenElement
    {
        #region Setup/Teardown

        [SetUp]
        public void SetUp()
        {
            _element = new ScreenElement<Control>(new Control());
        }

        #endregion

        private ScreenElement<Control> _element;

        [Test]
        public void Match_by_alias_if_the_label_test_fails()
        {
            var label = new Label();
            label.Text = "label1";

            _element.Label = ControlDriverFactory.GetDriver(label);
            _element.Alias = "alias1";

            _element.Matches("label1").ShouldBeTrue();
            _element.Matches("label2").ShouldBeFalse();
            _element.Matches("alias1").ShouldBeTrue();
            _element.Matches("alias2").ShouldBeFalse();
        }

        [Test]
        public void Matches_by_alias_alone_if_no_label()
        {
            _element.Alias = "alias1";

            _element.Matches("alias1").ShouldBeTrue();
            _element.Matches("alias2").ShouldBeFalse();
        }

        [Test]
        public void Matches_by_label_text_and_no_alias()
        {
            var label = new Label();
            label.Text = "label1";

            _element.Label = ControlDriverFactory.GetDriver(label);
            _element.Alias = null;

            _element.Matches("label1").ShouldBeTrue();
            _element.Matches("label2").ShouldBeFalse();
        }

        [Test]
        public void Should_disable_the_Control_if_the_ScreenElement_is_ReadOnly_regardless_of_the_ScreenState()
        {
            // Given
            _element.ActivationMode = ActivationMode.ReadOnly;

            // And
            _element.EnableControl(new StubScreenState {ControlIsEnabled = true});

            // Then
            _element.BoundControl.Enabled.ShouldBeFalse();

            // Given
            _element.EnableControl(new StubScreenState {ControlIsEnabled = false});

            // Then
            _element.BoundControl.Enabled.ShouldBeFalse();
        }


        [Test]
        public void Should_use_the_enable_function_after_readonly_is_set_to_false()
        {
            var label = new Label();
            LabelElement element = new LabelElement(ReflectionHelper.GetAccessor<LabelTarget>(x => x.Text), label);
            element.BindEnabledTo(ReflectionHelper.GetAccessor<LabelTarget>(x => x.Enabled));

            LabelTarget target = new LabelTarget(){Enabled = false};
            element.Bind(target);

            element.EnableControl(new EnableAllScreenState());
            label.Enabled.ShouldBeFalse();

            target.Enabled = true;
            element.EnableControl(new EnableAllScreenState());
            label.Enabled.ShouldBeTrue();
        }

        public class LabelTarget
        {
            public bool Enabled { get; set;}
            public string Text { get; set;}
        }


        [Test]
        public void Should_enable_the_Control_if_the_ScreenElement_is_AlwaysActive_regardless_of_the_ScreenState()
        {
            // Given
            _element.ActivationMode = ActivationMode.AlwaysActive;

            // And
            _element.EnableControl(new StubScreenState {ControlIsEnabled = true});

            // Then
            _element.BoundControl.Enabled.ShouldBeTrue();

            // Given
            _element.EnableControl(new StubScreenState {ControlIsEnabled = false});

            // Then
            _element.BoundControl.Enabled.ShouldBeTrue();
        }

        [Test]
        public void When_ActivationMode_is_normal_enable_by_the_ScreenState()
        {
            // Given
            _element.ActivationMode = ActivationMode.Normal;

            // And
            _element.EnableControl(new StubScreenState {ControlIsEnabled = true});

            // Then
            _element.BoundControl.Enabled.ShouldBeTrue();

            // Given
            _element.EnableControl(new StubScreenState {ControlIsEnabled = false});

            // Then
            _element.BoundControl.Enabled.ShouldBeFalse();
        }
    }


    internal class StubScreenState : IScreenState
    {
        public bool ControlIsHidden { get; set; }

        public bool ControlIsEnabled { get; set; }

        #region IScreenState Members

        public bool IsControlEnabled(object control)
        {
            return ControlIsEnabled;
        }

        #endregion

        public bool IsControlHidden(object control)
        {
            return ControlIsHidden;
        }
    }
}